/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _THRIFT_TCODING_H_
#define _THRIFT_TCODING_H_ 1

#ifndef __THRIFT_BYTE_ORDER
# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
#  define __THRIFT_BYTE_ORDER BYTE_ORDER
#  define __THRIFT_LITTLE_ENDIAN LITTLE_ENDIAN
#  define __THRIFT_BIG_ENDIAN BIG_ENDIAN
# else
#  include <boost/config.hpp>
#  include <boost/detail/endian.hpp>
#  define __THRIFT_BYTE_ORDER BOOST_BYTE_ORDER
#  ifdef BOOST_LITTLE_ENDIAN
#   define __THRIFT_LITTLE_ENDIAN __THRIFT_BYTE_ORDER
#   define __THRIFT_BIG_ENDIAN 0
#  else
#   define __THRIFT_LITTLE_ENDIAN 0
#   define __THRIFT_BIG_ENDIAN __THRIFT_BYTE_ORDER
#  endif
# endif
#endif

namespace apache {
  namespace thrift {

//
// encode as big endian
//
inline uint16_t TEncodeInt16BE(uint16_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
	return value;
#else
	uint16_t result;
	uint8_t* buf = (uint8_t*)&result;
	buf[1] = value & 0xff;
	buf[0] = (value >> 8) & 0xff;
	return result;
#endif
}

inline uint32_t TEncodeInt32BE(uint32_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
	return value;
#else
	uint32_t result;
	uint8_t* buf = (uint8_t*)&result;
	buf[3] = value & 0xff;
	buf[2] = (value >> 8) & 0xff;
	buf[1] = (value >> 16) & 0xff;
	buf[0] = (value >> 24) & 0xff;
	return result;
#endif
}

inline uint64_t TEncodeInt64BE(uint64_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
	return value;
#else
	uint64_t result;
	uint8_t* buf = (uint8_t*)&result;
	buf[7] = value & 0xff;
	buf[6] = (value >> 8) & 0xff;
	buf[5] = (value >> 16) & 0xff;
	buf[4] = (value >> 24) & 0xff;
	buf[3] = (value >> 32) & 0xff;
	buf[2] = (value >> 40) & 0xff;
	buf[1] = (value >> 48) & 0xff;
	buf[0] = (value >> 56) & 0xff;
	return result;
#endif
}

inline uint16_t TDecodeInt16BE(uint16_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
	return value;
#else
	uint8_t* ptr = (uint8_t*)&value;
	return ((static_cast<uint16_t>(static_cast<uint8_t>(ptr[1])))
		| (static_cast<uint16_t>(static_cast<uint8_t>(ptr[0])) << 8));
#endif
}

inline uint32_t TDecodeInt32BE(uint32_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
	return value;
#else
	uint8_t* ptr = (uint8_t*)&value;
	return ((static_cast<uint32_t>(static_cast<uint8_t>(ptr[3])))
		| (static_cast<uint32_t>(static_cast<uint8_t>(ptr[2])) << 8)
		| (static_cast<uint32_t>(static_cast<uint8_t>(ptr[1])) << 16)
		| (static_cast<uint32_t>(static_cast<uint8_t>(ptr[0])) << 24));
#endif
}

inline uint64_t TDecodeInt64BE(uint64_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_BIG_ENDIAN
	return value;
#else
	uint8_t* ptr = (uint8_t*)&value;
	return ((static_cast<uint64_t>(static_cast<uint8_t>(ptr[7])))
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[6])) << 8)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[5])) << 16)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[4])) << 24)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[3])) << 32)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[2])) << 40)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[1])) << 48)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[0])) << 56));

#endif
}

inline uint16_t TEncodeInt16LE(uint16_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
	return value;
#else
	uint16_t result;
	uint8_t* buf = (uint8_t*)&result;
	buf[0] = value & 0xff;
	buf[1] = (value >> 8) & 0xff;
	return result;
#endif
}

inline uint32_t TEncodeInt32LE(uint32_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
	return value;
#else
	uint32_t result;
	uint8_t* buf = (uint8_t*)&result;
	buf[0] = value & 0xff;
	buf[1] = (value >> 8) & 0xff;
	buf[2] = (value >> 16) & 0xff;
	buf[3] = (value >> 24) & 0xff;
	return result;
#endif
}

inline uint64_t TEncodeInt64LE(uint64_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
	return value;
#else
	uint64_t result;
	uint8_t* buf = (uint8_t*)&result;
	buf[0] = value & 0xff;
	buf[1] = (value >> 8) & 0xff;
	buf[2] = (value >> 16) & 0xff;
	buf[3] = (value >> 24) & 0xff;
	buf[4] = (value >> 32) & 0xff;
	buf[5] = (value >> 40) & 0xff;
	buf[6] = (value >> 48) & 0xff;
	buf[7] = (value >> 56) & 0xff;
	return result;
#endif
}

inline uint16_t TDecodeInt32LE(uint16_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
	return value;
#else
	uint8_t* ptr = (uint8_t*)&value;
	return ((static_cast<uint16_t>(static_cast<uint8_t>(ptr[0])))
		| (static_cast<uint16_t>(static_cast<uint8_t>(ptr[1])) << 8));
#endif
}

inline uint32_t TDecodeInt32LE(uint32_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
	return value;
#else
	uint8_t* ptr = (uint8_t*)&value;
	return ((static_cast<uint32_t>(static_cast<uint8_t>(ptr[0])))
		| (static_cast<uint32_t>(static_cast<uint8_t>(ptr[1])) << 8)
		| (static_cast<uint32_t>(static_cast<uint8_t>(ptr[2])) << 16)
		| (static_cast<uint32_t>(static_cast<uint8_t>(ptr[3])) << 24));
#endif
}

inline uint64_t TDecodeInt64LE(uint64_t value)
{
#if __THRIFT_BYTE_ORDER == __THRIFT_LITTLE_ENDIAN
	return value;
#else
	uint8_t* ptr = (uint8_t*)&value;
	return ((static_cast<uint64_t>(static_cast<uint8_t>(ptr[0])))
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[1])) << 8)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[2])) << 16)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[3])) << 24)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[4])) << 32)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[5])) << 40)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[6])) << 48)
		| (static_cast<uint64_t>(static_cast<uint8_t>(ptr[7])) << 56));
#endif
}

}
}

#endif
